package com.sunday.common.http.apache;

import com.sunday.common.core.remoting.base.response.Response;
import com.sunday.common.core.remoting.rest.response.RestResponse;
import com.sunday.common.http.apache.async.AsyncHttpClientPoolUtils;
import com.sunday.common.http.apache.async.DefaultFutureCallback;
import com.sunday.common.http.apache.sync.HttpClientPoolUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/http/api")
public class HttpServerApi {

//    static final CloseableHttpClient httpclient;
//
//    static {
//        httpclient = getHttpClient();
//    }
//
//    public static CloseableHttpClient getHttpClient() {
//
//        HttpClientPoolBuilder.RequestBuilder requestBuilder = HttpClientPoolBuilder.RequestBuilder.create();
//        requestBuilder.setResponseTimeout(Timeout.ofSeconds(1));
//        requestBuilder.setConnectionRequestTimeout(Timeout.ofSeconds(1));
//        requestBuilder.setConnectTimeout(Timeout.ofSeconds(1));
//
//        HttpClientPoolBuilder.ConnectionManagerBuilder connectionManagerBuilder = HttpClientPoolBuilder.ConnectionManagerBuilder.create();
//        connectionManagerBuilder.setMaxPerRoute(100);
//        connectionManagerBuilder.setMaxTotal(1000);
//
//        HttpClientPoolBuilder httpClientPoolBuilder = HttpClientPoolBuilder.create(requestBuilder.requestConfig(), connectionManagerBuilder.connectionManager(), SentinelApacheHttpClientConfig.create());
//        CloseableHttpClient httpClient = httpClientPoolBuilder.httpClientBuilder().build();
//        return httpClient;
//    }

//    static final CloseableHttpAsyncClient httpAsyncClient;
//
//    static {
//        httpAsyncClient = getHttpAsyncClient();
//    }
//
//    public static CloseableHttpAsyncClient getHttpAsyncClient() {
//        AsyncHttpClientPoolBuilder.RequestBuilder requestBuilder = AsyncHttpClientPoolBuilder.RequestBuilder.create();
//        requestBuilder.setResponseTimeout(Timeout.ofSeconds(1));
//        requestBuilder.setConnectionRequestTimeout(Timeout.ofSeconds(1));
//        requestBuilder.setConnectTimeout(Timeout.ofSeconds(1));
//
//        AsyncHttpClientPoolBuilder.ConnectionManagerBuilder connectionManagerBuilder = AsyncHttpClientPoolBuilder.ConnectionManagerBuilder.create();
//        connectionManagerBuilder.setMaxPerRoute(100);
//        connectionManagerBuilder.setMaxTotal(1000);
//
//        AsyncHttpClientPoolBuilder asyncHttpClientPoolBuilder = AsyncHttpClientPoolBuilder.create(requestBuilder.requestConfig(), connectionManagerBuilder.connectionManager());
//        CloseableHttpAsyncClient httpAsyncClient = asyncHttpClientPoolBuilder.httpAsyncClient();
//        httpAsyncClient.start();
//        return httpAsyncClient;
//    }

    @GetMapping("get/sleep30")
    public RestResponse sleep30(HttpServletRequest request) throws InterruptedException {
        log.info("{}", request.getRequestURI());
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            log.info("HEAD : {} ==== {}", key, request.getHeader(key));
        }
        request.getParameterMap().forEach((k, v) -> log.info("PARAM : {} ==== {}", k, v));
        TimeUnit.SECONDS.sleep(30);
        return RestResponse.ok();
    }

    @GetMapping("get/sleep5")
    public RestResponse sleep5(HttpServletRequest request) throws InterruptedException {
        log.info("{}", request.getRequestURI());
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            log.info("HEAD : {} ==== {}", key, request.getHeader(key));
        }
        request.getParameterMap().forEach((k, v) -> log.info("PARAM : {} ==== {}", k, v));
        TimeUnit.SECONDS.sleep(5);
        return RestResponse.ok();
    }

    @GetMapping("get/sleep3")
    public RestResponse sleep3(HttpServletRequest request) throws InterruptedException {
        log.info("{}", request.getRequestURI());
        TimeUnit.SECONDS.sleep(3);
        return RestResponse.ok();
    }

    @GetMapping("get/sleep2")
    public RestResponse sleep2(HttpServletRequest request) throws InterruptedException {
        log.info("{}", request.getRequestURI());
        TimeUnit.SECONDS.sleep(2);
        return RestResponse.ok();
    }

    @GetMapping("get/sleep1")
    public RestResponse sleep1(HttpServletRequest request) throws InterruptedException {
        log.info("{}", "=========================");
        TimeUnit.SECONDS.sleep(1);
        return RestResponse.ok();
    }

    @GetMapping("get/sleep20ms")
    public RestResponse sleep20ms(HttpServletRequest request) throws InterruptedException {
        log.info("{}", "=========================");
        TimeUnit.MILLISECONDS.sleep(20);
        return RestResponse.ok();
    }

    @PostMapping("post/forJson")
    public RestResponse forJson(HttpServletRequest request, @RequestBody JsonEntity jsonEntity) throws InterruptedException {
        Random random = new Random();
        int s = random.nextInt(50);
        log.info("{}", s);
        TimeUnit.MILLISECONDS.sleep(s);
        return RestResponse.ok();
    }


    @GetMapping("get/sleep")
    public RestResponse sleep(HttpServletRequest request) {
        log.info("{}", request.getRequestURI());
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            log.info("HEAD : {} ==== {}", key, request.getHeader(key));
        }
        request.getParameterMap().forEach((k, v) -> log.info("PARAM : {} ==== {}", k, v));
        return RestResponse.ok();
    }

    @GetMapping("get/easy")
    public RestResponse easy(HttpServletRequest request) {
        log.info("{}", "=========================");
        return RestResponse.ok();
    }

    @PostMapping("post/easy")
    public RestResponse easyPost(HttpServletRequest request) {
        log.info("{}", "=========================");
        return RestResponse.ok();
    }


    @PostMapping("post/map")
    public RestResponse map(HttpServletRequest request) {
        log.info("{}", request.getRequestURI());
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            log.info("HEAD : {} ==== {}", key, request.getHeader(key));
        }
        request.getParameterMap().forEach((k, v) -> log.info("PARAM : {} ==== {}", k, v));
        return RestResponse.ok();
    }

    @PostMapping("post/json")
    public RestResponse json(HttpServletRequest request, @RequestBody JsonEntity jsonEntity) {
        log.info("{}", request.getRequestURI());
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            log.info("HEAD : {} ==== {}", key, request.getHeader(key));
        }
        log.info("PARAM : {}", jsonEntity);
        return RestResponse.ok();
    }

    /**
     * 乱码详见
     * org.apache.hc.client5.http.entity.mime.HttpRFC7578Multipart#formatMultipartHeader(org.apache.hc.client5.http.entity.mime.MultipartPart, java.io.OutputStream)
     */
    @PostMapping("post/multipart")
    public RestResponse multipart(HttpServletRequest request, @RequestParam(value = "Data") String data) {
        log.info("{}", request.getRequestURI());
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            log.info("HEAD : {} ==== {}", key, request.getHeader(key));
        }
        log.info("PARAM : {}", data);
        log.info("CLASS : {}", request.getClass());
        MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> multipartFileMap = multipartHttpServletRequest.getFileMap();
        multipartFileMap.forEach((k, v) -> {
            log.info("name : {}", k);
            log.info("MultipartFile name : {}, originalFilename : {}, ContentType : {}", v.getName(), v.getOriginalFilename(), v.getContentType());
            try {
                log.info("{}", java.net.URLDecoder.decode(v.getOriginalFilename(), "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
//            if (v.getOriginalFilename().endsWith(".txt")) {
//                try {
//                    log.info("{}", new String(v.getBytes(), "UTF-8"));
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
        });
        return RestResponse.ok();
    }

    /*************************************************   测试Sentinel   ********************************************************/

    @RequestMapping("/httpclient/sync")
    public Response sync() throws Exception {
        String url = "http://127.0.0.1:16500/http/api/get/easy";
//        String url = "http://127.0.0.1:16500/http/api/get/sleep2";
//        Response response = HttpResponseHandler.invoke(() -> HttpClientPoolUtils.doGet(url, httpclient));
        Response response = HttpResponseHandler.invoke(() -> HttpClientPoolUtils.doGet(url));
        log.info("{}", response);
        return response;
    }

    @RequestMapping("/httpclient/async")
    public Response async() throws Exception {

        DefaultFutureCallback futureCallback = new DefaultFutureCallback();

        String url = "http://127.0.0.1:16500/http/api/get/sleep2";
        Future<SimpleHttpResponse> future = AsyncHttpClientPoolUtils.doGet(
                url,
                DefaultFutureCallback.of(httpResult -> {
                    Response<HttpResult> response = HttpResponseHandler.invoke(() -> httpResult);
                    log.info("{}", response);
                }));
//        log.info("Future<SimpleHttpResponse> : {}", future.get());
        HttpResult httpResult = futureCallback.universalTranslator(future.get());
        return HttpResponseHandler.invoke(() -> httpResult);
    }

}